use hashbrown::HashMap;
use honeybee::prelude::*;
use honeybee::Result;

#[derive(Default)]
pub struct Apps {
    apps: HashMap<String, Addr<TcpStreamActor>>,
}

impl Service for Apps {}

#[async_trait::async_trait]
impl Actor for Apps {
    fn name(&self) -> &str {
        "Apps"
    }

    async fn started(&mut self, ctx: &mut Context<Self>) -> Result<()> {
        info!("{} started", self.name());
        let router = ctx.get_router().await?;
        router.register::<proto::AllUserMessageForward>();
        router.register::<proto::AllUserMessageApp>();
        Ok(())
    }

    async fn stopped(&mut self, _ctx: &mut Context<Self>) {
        info!("{} stoped", self.name());
    }
}

#[message]
pub struct AppConnected(pub String, pub Addr<TcpStreamActor>);
#[async_trait::async_trait]
impl Handler<AppConnected> for Apps {
    async fn handle(&mut self, _ctx: &mut Context<Self>, msg: AppConnected) -> Result<()> {
        let (app_name, stream) = (msg.0, msg.1);
        info!("app:{} connected", app_name);
        self.apps
            .entry(app_name)
            .and_modify(|e| *e = stream.clone())
            .or_insert(stream);
        Ok(())
    }
}

#[async_trait::async_trait]
impl Handler<NetMsg<proto::AllUserMessageForward>> for Apps {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NetMsg<proto::AllUserMessageForward>,
    ) -> Result<()> {
        let msg = msg.msg;
        let msg_id = msg.msg_id;
        for (app_name, app_stream) in self.apps.iter() {
            if let Err(err) = app_stream.send_remote(msg.clone()) {
                error!(
                    "send all user msg:{} app_name:{} err:{}",
                    msg_id, app_name, err
                );
            }
        }
        Ok(())
    }
}

#[async_trait::async_trait]
impl Handler<NetMsg<proto::AllUserMessageApp>> for Apps {
    async fn handle(
        &mut self,
        _ctx: &mut Context<Self>,
        msg: NetMsg<proto::AllUserMessageApp>,
    ) -> Result<()> {
        let msg = msg.msg;
        let msg_id = msg.msg_id;
        for (app_name, app_stream) in self.apps.iter() {
            if let Err(err) = app_stream.send_remote(msg.clone()) {
                error!(
                    "send all app user msg:{} app_name:{} err:{}",
                    msg_id, app_name, err
                );
            }
        }
        Ok(())
    }
}

#[message]
pub struct GmsgNotify {
    pub object_id: String,
    pub msg_type: gmsg_db::GmsgType,
    pub msg_bytes: Vec<u8>,
    pub expire_time: i64,
}
#[async_trait::async_trait]
impl Handler<GmsgNotify> for Apps {
    async fn handle(&mut self, _ctx: &mut Context<Self>, msg: GmsgNotify) -> Result<()> {
        for (app_name, app_stream) in self.apps.iter() {
            if let Err(err) = app_stream.send_remote(proto::NewGmsgNotify {
                object_id: msg.object_id.clone(),
                msg_type: msg.msg_type,
                msg_bytes: msg.msg_bytes.clone(),
                expire_time: msg.expire_time,
            }) {
                error!(
                    "send gmsg object_id:{} msg_type:{:?} app_name:{} err:{}",
                    msg.object_id, msg.msg_type, app_name, err
                );
            }
        }
        Ok(())
    }
}
